<script setup lang="ts">
import { Download, Filter } from '@element-plus/icons-vue'
import { omit } from 'lodash-es'
import type { ViewTableProps } from './type'
import { useSimpleExportLists } from './useSimpleExportLists'
import { ViewTableColumn } from './ViewTableColumn'
import type { TableScopedColumn } from '@/types'

defineOptions({
  name: 'ViewTable',
  inheritAttrs: false,
})
const props = withDefaults(
  defineProps<ViewTableProps<any> & { showDownload?: boolean }>(),
  {
    excel: false,
    preview: false,
    showToolbox: true,
    showHeader: true,
    showOverflowTooltip: true, // 数据单行显示
    operateWidth: '100',
    fit: true,
    customDownload: false,
    tooltipOptions: () => ({
      enterable: true,
      placement: 'top',
      showArrow: true,
      hideAfter: 200,
      popperClass: 'max-w-300px',
      popperOptions: { strategy: 'fixed' },
    }),
    tooltipEffect: 'dark',
    selectOnIndeterminate: true,
    treeProps: () => ({
      hasChildren: 'hasChildren',
      children: 'children',
    }),
    loading: false,
    tableLayout: 'fixed',
    indent: 16,
    rowKey: 'id',
    emptyText: '一点都没有了！',
    showDownload: true,
  },
)
const emits = defineEmits<{
  download: []
}>()

// 显示声明插槽类型
defineSlots<{
  operate: (props: {
    row: any
    column: TableScopedColumn
    index: number
  }) => void
  actions: () => void
  [key: string]: (...args: any[]) => void
}>()

const [isTooltip, setIsTooltip] = useState(false)
const [tooltipVirtualElement, setTooltipVirtualElement]
  = useState<HTMLElement | null>(null)
const [currentErrorMessage, setCurrentErrorMessage]
  = useState('')
const [checkedKeys, setCheckedKeys] = useState<string[]>(
  [],
)

const route = useRoute()

/** 当前渲染生成组件的唯一标识 */
const scopeId = useScopeId()
const errorCellMap: Map<
  `${number}_${number}`,
  {
    errorMessage: string
    target: HTMLElement
  }
> = new Map()

const checkedColumns = computed(() => {
  return props.columns.filter(v =>
    checkedKeys.value.includes(v.key),
  )
})

watchEffect(() => {
  setCheckedKeys(
    props.columns.filter(v => !v.hidden).map(v => v.key),
  )
})

function clickDownload() {
  if (props.customDownload) {
    emits('download')
    return
  }
  const { exportXlsx } = useSimpleExportLists<any>({
    columns: checkedColumns.value,
    lists: props.data ?? props.lists ?? [],
  })

  exportXlsx(route.meta.title)
}

function errorCell(rowIndex: number, colIndex: number, errorMessage = '') {
  const target = document.querySelector(
    `.el-table[${scopeId}] tbody[tabindex='-1'] tr:nth-of-type(${rowIndex}) td:nth-of-type(${colIndex})`,
  ) as HTMLElement
  if (target) {
    setTooltipVirtualElement(target as any)
    setIsTooltip(true)
  }
  // console.log(target);
  const key: `${number}_${number}` = `${rowIndex}_${colIndex}`
  errorCellMap.set(key, {
    errorMessage,
    target,
  })
  setCurrentErrorMessage(errorMessage)
  target.classList.add('error')
  // // 创建 <style> 元素
  // const style = document.createElement('style');

  // // 设置样式内容
  // style.innerHTML = `
  // .el-table[${scopeId}]  tbody[tabindex='-1'] {
  //     tr:nth-of-type(${rowIndex}) td:nth-of-type(${colIndex})::before {
  //       outline-color: var(--el-color-danger) !important;
  //       opacity: 1;
  //     }
  //   }
  // `;

  // 将 <style> 元素添加到 <head> 元素中
  // document.head.appendChild(style);
  return () => {
    // 将 <style> 元素从 <head> 元素中移除
    // document.head.removeChild(style);
    target.classList.remove('error')
    errorCellMap.delete(key)
    setIsTooltip(false)
  }
}
function handleCellMouseEnter(_: any, __: any, cell: any) {
  if (!props.excel)
    return
  const m = [...errorCellMap.values()]
  const n = m.find(item => item.target.isEqualNode(cell))
  if (!n)
    return
  setIsTooltip(true)
  setTooltipVirtualElement(n.target)
  setCurrentErrorMessage(n.errorMessage)
  // console.log(row, column, cell);
}
function handleCellMouseLeave() {
  if (!props.excel)
    return
  setIsTooltip(false)
}
function validate() {
  if (!props.rules) {
    if (errorCellMap.size === 0)
      return true
    return false
  }
  const columnsProps = props.columns.map(item => item.prop)
  for (const rowIndex in props.data) {
    const row = props.data[rowIndex as unknown as number]
    for (const key in row) {
      if (!Reflect.has(props.rules ?? {}, key))
        continue
      const m = Reflect.get(props.rules!, key)
      const isValid = m?.validator({
        role: m,
        row,
        value: row[key],
      })
      if (isValid)
        continue
      const colIndex = columnsProps.findIndex(item =>
        (item as string).includes(key),
      )
      errorCell(+rowIndex + 1, colIndex + 1, m?.message)
    }
  }
  return false
}
function toSlotName(key: any, isHeader = false): string {
  return (isHeader ? `${key}Header` : key) as string
}

defineExpose({
  export: clickDownload,
  errorCell,
  validate,
})
</script>

<template>
  <div
    v-if="$slots.actions || showToolbox"
    class="width-fill lists-head flex"
  >
    <div
      v-if="$slots.actions"
      class="lists-actions flex-fillRemaining"
    >
      <slot name="actions" />
    </div>
    <div
      v-if="showToolbox"
      class="margin-left-auto flex-incompressible lists-toolbox self-end"
    >
      <ElPopover :teleported="true" :width="popoverWidth">
        <template #reference>
          <ElButton
            type="primary"
            :icon="Filter"
            circle
          />
        </template>
        <BScrollbar style="max-height: 40vh">
          <ElCheckboxGroup
            v-model="checkedKeys"
            class="view-table-toolbox-checkbox-group"
          >
            <ElCheckbox
              v-for="column in columns"
              :key="column.key"
              :value="column.key"
              :disabled="column.type !== undefined"
              style="display: flex"
              class="overflow width-fill view-table-toolbox-checkbox"
            >
              {{ column.label }}
            </ElCheckbox>
          </ElCheckboxGroup>
        </BScrollbar>
      </ElPopover>
      <ElTooltip v-if="showDownload" content="导出" placement="top">
        <ElButton
          class="margin-left-xs"
          type="success"
          :icon="Download"
          circle
          @click="clickDownload"
        />
      </ElTooltip>
    </div>
  </div>
  <div class="flex-fillRemaining width-fill height-fill alpha-block view-table overflow-auto p-[10px]">
    <ElTable
      v-loading="loading"
      element-loading-custom-class="global-loading"
      v-bind="{
        ...omit(
          props,
          'loading',
          'columns',
          'showToolbox',
          'popoverWidth',
          'operateWidth',
        ),
        ...$attrs,
      }"
      :data="data ?? lists"
      height="100%" border
      :class="[{ excel, preview }]"
      @contextmenu.prevent.stop
      @cell-mouse-enter="handleCellMouseEnter"
      @cell-mouse-leave="handleCellMouseLeave"
    >
      <template #empty>
        <TableEmpty />
      </template>
      <template
        v-for="item in checkedColumns"
      >
        <!-- 一级 -->
        <template
          v-if="
            item.prop
              && (!item.children || item.children.length === 0)
          "
        >
          <ElTableColumn
            :key="item.key"
            v-bind="
              omit(item, 'children', 'render', 'header', 'hidden') as any
            "
          >
            <template #default="scoped">
              <slot
                v-if="$slots[toSlotName(item.prop)]"
                :name="toSlotName(item.prop)"
                :row="scoped.row"
                :column="scoped.column"
                :index="scoped.index"
              >
                <RenderComponent
                  v-if="item.render"
                  :render="item.render"
                  :row="scoped.row"
                  :column="scoped.column"
                  :index="scoped.$index"
                />
              </slot>

              <RenderComponent
                v-else-if="item.render"
                :render="item.render"
                :row="scoped.row"
                :column="scoped.column"
                :index="scoped.$index"
              />
            </template>
            <template #header="scoped">
              <slot
                v-if="$slots[toSlotName(item.prop, true)]"
                :name="toSlotName(item.prop, true)"
                :row="scoped.row"
                :column="scoped.column"
                :index="scoped.index"
              >
                <RenderComponent
                  v-if="item.header"
                  :row="null"
                  :render="item.header"
                  :column="scoped.column"
                  :index="scoped.$index"
                />
              </slot>
              <RenderComponent
                v-else-if="item.header"
                :row="null"
                :render="item.header"
                :column="scoped.column"
                :index="scoped.$index"
              />
            </template>
          </ElTableColumn>
        </template>
        <ViewTableColumn v-else :key="item.key" v-bind="(item as any)" />
      </template>
      <ElTableColumn
        v-if="$slots.operate"
        label="操作"
        fixed="right"
        prop="operate"
        align="center"
        :show-overflow-tooltip="false"
        :width="operateWidth"
      >
        <template #default="scoped">
          <slot
            name="operate"
            :row="scoped.row"
            :column="scoped.column"
            :index="scoped.$index"
          />
        </template>
      </ElTableColumn>
    </ElTable>
  </div>
  <el-tooltip
    :visible="isTooltip && excel"
    :popper-options="{
      modifiers: [
        {
          name: 'computeStyles',
          options: {
            adaptive: false,
            enabled: false,
          },
        },
      ],
    }"
    :virtual-ref="tooltipVirtualElement as any"
    virtual-triggering
    popper-class="view-table-tooltip"
    effect="customized"
  >
    <template #content>
      <span>{{ currentErrorMessage }}</span>
    </template>
  </el-tooltip>
</template>

<style lang="scss" scoped>
//------------------组件样式------------------
.lists-actions {
  & > :not(form) {
    margin-bottom: 18px;
  }
}
.lists-toolbox {
  margin-bottom: 18px;
}
//-------------样式穿透-------------
</style>

<style lang="scss">
.view-table-toolbox-checkbox {
  .el-checkbox__label {
    flex: 1 1 auto;
    overflow: hidden;
    /* 文本不会换行 */
    white-space: nowrap;
    /* 显示省略符号来代表被修剪的文本 */
    text-overflow: ellipsis;
  }
}
.view-table-tooltip.is-customized {
  /* Set padding to ensure the height is 32px */
  padding: 6px 12px;
  color: var(--el-color-danger);
  background: var(--el-color-danger-light-9);
  .el-popper__arrow::before {
    background: var(--el-color-danger-light-9);
    color: var(--el-color-danger);
    right: 0;
  }
}
.view-table-description {
  font-size: 14px;
  color: var(--el-text-color-secondary);
  p:not(.title) {
    text-indent: 1em;
  }
}
%cell {
  padding: 0px;
  cursor: cell;
  position: relative;
  &::before {
    // cursor: cell;
    opacity: 0;
    transition: all 0.2s var(--motion-bezier);
    content: '';
    position: absolute;
    top: 0px;
    left: 0px;
    z-index: 9;
    width: 100%;
    height: 100%;
    outline: 1px solid var(--el-text-color-disabled);
    outline-offset: -2px;
    // background-color: red;
    box-sizing: border-box;
    pointer-events: none;
  }
}
//! 添加一个可选中状态
.view-table {
  .el-table__body {
    .el-table__cell.cell {
      @extend %cell;
      &:hover::before {
        opacity: 0.8;
      }
    }
    .el-table__cell.cell.select {
      &::before {
        opacity: 0.8;
        outline-color: var(--el-color-primary);
      }
    }
  }
}
//! -----------------
.view-table.excel {
  --el-table-header-bg-color: var(--el-bg-color-page);
  tbody[tabindex='-1'] tr td.error::before {
    outline-color: var(--el-color-danger) !important;
    opacity: 1;
  }
  .el-table__body {
    .el-table__cell {
      @extend %cell;
    }
    .el-table__cell[class]:not(
        .el-table_1_column_1
      ):hover::before {
      opacity: 0.8;
    }
    .el-table__cell[class]:not(
        .el-table_1_column_1
      ):focus-within::before {
      opacity: 1;
      outline-color: var(--el-color-primary);
    }
  }
  [class].cell {
    // height: 100%;
    // width: 100%;
    padding: 0px;
    min-height: 40px;
    line-height: 40px;
    // display: grid;
    // place-content: center;
    text-align: center;
    // cursor: cell;
  }
  .cell > .el-input[class] {
    width: 100% !important;
    height: 100% !important;
    min-height: 40px;
    .el-input__wrapper {
      box-shadow: none;
      background-color: transparent;
      // cursor: cell;
      outline: none;
    }
    input {
      text-align: center;
      // cursor: cell;
    }
  }
  .el-input[class].is-disabled {
    cursor: not-allowed;
    .el-input__wrapper[class],
    input[class] {
      cursor: not-allowed;
    }
  }
}
.view-table.excel.preview {
  .el-table__body {
    .el-table__cell {
      cursor: context-menu !important;
    }
    .el-table__cell[class]:not(
        .el-table_1_column_1
      ):hover::before {
      opacity: 0 !important;
    }
    .el-table__cell[class]:not(
        .el-table_1_column_1
      ):focus-within::before {
      opacity: 0 !important;
    }
  }
  .el-input[class].is-disabled {
    cursor: context-menu !important;
    .el-input__wrapper[class],
    input[class] {
      cursor: context-menu !important;
    }
  }
}
</style>
